/**
 * @file
 * @author dousha
 * @date 2020/11/30.
 */

#include "entropy.h"
#include "../Logic/linear_feedback_shift_register.h"
#include <string.h>

static uint8_t mess[MESS_SIZE] = {0};
static uint8_t needle = 0, probe = 0;
static uint8_t buf = 0, count = 0;

void entropy_init(ADC_HandleTypeDef *adc) {
	memset(mess, 0, MESS_SIZE);
	lfsr_init(LFSR_SEED);
	HAL_ADC_Start_IT(adc);
}

uint8_t entropy_read() {
	lfsr_step();
	return lfsr_get_byte();
}

void entropy_feed(uint8_t v) {
	mess[needle] = v;
	if (++needle >= MESS_SIZE) {
		needle = 0;
	}
}

uint32_t entropy_harvest() {
	if ((needle > probe && (needle - probe < 4)) || (needle < probe && (needle + MESS_SIZE - probe < 4))) {
		return 0;
	} else {
		uint32_t out = 0;
		for (uint8_t i = 0; i < 4; i++) {
			out |= mess[probe + i >= MESS_SIZE ? probe + i - MESS_SIZE : probe + i];
			out <<= 8u;
		}
		probe += 4;
		if (probe >= MESS_SIZE) {
			probe -= MESS_SIZE;
		}
		return out;
	}
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *adc) {
	uint32_t value = HAL_ADC_GetValue(adc);
	buf <<= 2u;
	buf |= (value & 3u); // grab the least significant bit, which should be drown by noise
	++count;
	if (count % 4 == 0 && count != 0) {
		mess[needle] = buf;
		if (++needle >= MESS_SIZE) {
			needle = 0;
		}
	}
	if (count % 12 == 0) {
		value = entropy_harvest();
		if (value != 0) {
			lfsr_init(value);
		}
	}
	HAL_ADC_Start_IT(adc);
}
